import requests
import json
# from lxml import etree
import ffmpeg
import os, re
import wget
import urllib.request
import zjl_util
import time

requests.packages.urllib3.disable_warnings()

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3970.5 Safari/537.36',
    'Referer': 'https://www.bilibili.com/'
}
pat0 = '"episodes":\\s{0,3}\\[(.*?)\\]'
pat = '"title":\\s{0,3}"(.*?)".*?"bvid":\\s{0,3}"(.*?)"'


def get_video_list(homeurl, session=requests.session()):
    # 直接匹配会很卡，所以做两次匹配
    t = session.get(url=homeurl, headers=headers, verify=False).text
    # file_path = 'd:/code/pycrawlers/bibili.html'
    # f = open(file_path, encoding='utf-8')
    # t = ''.join(f.readlines())
    # f.close()
    r0 = re.compile(pat0, re.S).findall(t)
    video_infos = []
    for ri in r0:
        r = re.compile(pat, re.S).findall(ri)
        for i in r:
            if i not in video_infos:
                video_infos.append(i)
    return video_infos


def GetBiliVideo(homeurl,num,session=requests.session()):
    res = session.get(url=homeurl, headers=headers, verify=False)
    doc = res.text
    v_pat = '"video":.*?"baseUrl":\\s{0,3}"(.*?)"'
    a_pat = '"audio":.*?"baseUrl":\\s{0,3}"(.*?)"'
    name_pat = '"videoData".*?"title":\\s{0,3}"(.*?)"'
    #    html = etree.HTML(res.content)
    #    videoinforms = str(html.xpath('//head/script[4]/text()')[0])[20:]
    #    videojson = json.loads(videoinforms)
    # 获取详情信息列表
    #listinform = str(html.xpath('//head/script[4]/text()')[0])
    # listinform = str(html.xpath('//head/script[4]/text()')[0].encode('ISO-8859-1').decode('utf-8'))[20:-122]
    #    pattern = '.__playinfo__=(.*)</script><script>window.__INITIAL_STATE__='
    # listinform = str(html.xpath('//head/script[4]/text()')[0].encode().decode('utf-8'))[20:-122]
    # listinform = re.findall(pattern, res.text)[0]
    #    listinform = str(html.xpath('//head/script[4]/text()')[0].encode().decode('utf-8'))[20:]
    # print(listinform)
    #    listjson=json.loads(listinform)
    # 获取视频链接和音频链接
    try:
        # 2018年以后的b站视频，音频和视频分离
        #    VideoURL = videojson['data']['dash']['video'][0]['baseUrl']
        #    AudioURl = videojson['data']['dash']['audio'][0]['baseUrl']
        VideoURL = re.compile(v_pat, re.S).findall(doc)[0]
        AudioURl = re.compile(a_pat, re.S).findall(doc)[0]
        flag=0
    except Exception:
        # 2018年以前的b站视频，格式为flv
        #    VideoURL = videojson['data']['durl'][0]['url']
        VideoURL = re.compile(v_pat, re.S).findall(doc)[0]
        flag=1
    # 获取文件夹的名称
    #    dir_name = str(html.xpath("//h1/@title")[0].encode().decode('utf-8'))
    dir_name = re.compile(name_pat, re.S).findall(doc)[0]
    dir_name = dir_name.replace('\xa0', '').replace('|', '').replace('?', '').replace('？', '').replace('/', '').replace('..', '.').replace('..', '.').replace('..', '.').replace('《', '').replace('》', '').replace('\\u002F', '')
    if not os.path.exists(dir_name):
        # 如果不存在则创建目录
        # 创建目录操作函数
        os.makedirs(dir_name)
        print('目录文件创建成功!')
    # 获取每一集的名称
    #    listinform2 = str(html.xpath('//head/script[5]/text()')[0].encode().decode('utf-8'))[25:]
    #    listinform2 = listinform2.replace(';(function(){var s;(s=document.currentScript||document.scripts[document.scripts.length-1]).parentNode.removeChild(s);}());', '')
    # print(listinform2)
    #    listjson2 = json.loads(listinform2)
    #    name = listjson2['videoData']['pages'][num]['part']
    #    name = name.replace('\xa0', '').replace('|', '').replace('?', '').replace('？', '').replace('/', '_')
    name = dir_name[:20]
    print(name)
    # 下载视频和音频
    if flag == 0:
        print('正在下载 "'+name+'" 的音频····')
        # headers.update({'Referer': homeurl})
        # opener = urllib.request.build_opener()
        # opener.addheaders = [headers]
        # urllib.request.install_opener(opener)
        # wget.download(AudioURl, os.getcwd()+'/'+dirname+'/'+name+ '_Audio.mp3')
        
        headers.update({'Referer': homeurl})
        zjl_util.download(AudioURl, os.getcwd()+'/'+dir_name+'/'+name + '_Audio.mp3', header=headers)
        print(flag, '正在下载 "'+name+'" 的视频····')
        zjl_util.download(VideoURL, os.getcwd()+'/'+dir_name+'/'+name + '_Video.mp4', header=headers)
        
        # BiliBiliDownload(homeurl=homeurl,url=AudioURl, name=os.getcwd()+'/'+dirname+'/'+name+ '_Audio.mp3', session=session)
    else:
        print('正在下载 "'+name+'" 的视频····')
        BiliBiliDownload(homeurl=homeurl,url=VideoURL, name=os.getcwd()+'/'+dir_name+'/'+name + '_Video.mp4', session=session)
    print('正在组合 "'+name+'" 的视频和音频····')
    CombineVideoAudio(os.getcwd()+'/'+dir_name+'/'+name + '_Video.mp4', os.getcwd()+'/'+dir_name+'/'+name+ '_Audio.mp3', os.getcwd()+'/'+dir_name + '.mp4')
    print(' "'+name+'" 下载完成！')


def BiliBiliDownload(homeurl,url, name, session=requests.session()):
    headers.update({'Referer': homeurl})
    session.options(url=url, headers=headers,verify=False)
    # 每次下载1M的数据
    begin = 0
    end = 1024*512-1
    flag=0
    while True:
        headers.update({'Range': 'bytes='+str(begin) + '-' + str(end)})
        res = session.get(url=url, headers=headers,verify=False)
        if res.status_code != 416:
            begin = end + 1
            end = end + 1024*512
        else:
            headers.update({'Range': str(end + 1) + '-'})
            res = session.get(url=url, headers=headers,verify=False)
            flag=1
        with open(name, 'ab') as fp:
            fp.write(res.content)
            print('get ', len(res.content))
            fp.flush()

        # data=data+res.content
        if flag==1:
            fp.close()
            break


def CombineVideoAudio(videopath,audiopath,outpath):
    # ffmpeg.video.combine_audio(videopath,audiopath,outpath)
    # ffmpeg.video.video_ins_mute_audio(videopath,audiopath,outpath)
    process = (
        ffmpeg.output(ffmpeg.input(videopath), ffmpeg.input(audiopath), filename=outpath, c='copy').overwrite_output()
    )
    ffmpeg_path = 'ffmpeg.exe'
    # process.run(ffmpeg_path)
    process.run_async(cmd=ffmpeg_path, pipe_stdin=True, pipe_stdout=False, pipe_stderr=False)
    # time.sleep(1)
    # os.remove(videopath)
    # os.remove(audiopath)


if __name__ == '__main__':

    # bvid = BV1Ub411N7d4
    bvid = input('请输入视频号：')
    # av = input('请输入视频号：')
    # url='https://www.bilibili.com/video/'+av
    # # 视频选集
    # range_start=input('从第几集开始？')
    # range_end = input('到第几集结束？')
    # if int(range_start)<=int(range_end):
    #     for i in range(int(range_start),int(range_end)+1):
    #         GetBiliVideo(url+'?p='+str(i),i-1)
    # 
    # else:
    #     print('选集不合法！')
    url = 'https://www.bilibili.com/video/' + bvid + '/?spm_id_from=333.788&vd_source=a248f44e3c87683800d8c8bac20ed6b4'
    title_bvid_s = get_video_list(url)
    for i in range(0, len(title_bvid_s)):
        title_bvid = title_bvid_s[i]
        print(i + 1, ' ', title_bvid[0], ': ', title_bvid[1])
    range_start = input('从第几集开始？')
    range_end = input('到第几集结束？')
    if int(range_start) <= int(range_end):
        for i in range(int(range_start), int(range_end)+1):
            video_url = 'https://www.bilibili.com/video/' + title_bvid_s[i-1][1] + '/?spm_id_from=333.788&vd_source=a248f44e3c87683800d8c8bac20ed6b4'
            GetBiliVideo(video_url, 0)
    # GetBiliVideo(url, 0)
